package com.horizon.cloud.standard.config;

import com.horizon.cloud.standard.properties.RedisRateLimitProperties;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@EnableCaching
@Configuration
@AutoConfigureBefore(RedisAutoConfiguration.class)
@EnableConfigurationProperties(RedisRateLimitProperties.class)
@ConditionalOnClass({RedisTemplate.class})
@Import({JedisConnectionConfiguration.class})
public class CustomedRedisAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean({RedisTemplate.class})
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        /**
         * redis 序列化器
         * RedisTemplate默认的序列化类是JdkSerializationRedisSerializer
         * 用JdkSerializationRedisSerializer序列化的话，
         * 被序列化的对象必须实现Serializable接口
         * 在存储内容时，除了属性的内容外还存了其他内容在里面，总长度长，且不宜阅读
         *
         * Jackson2JsonRedisSerializer和GenericJackson2JsonRedisSerializer
         * 两者都能序列化成json。但是
         * GenericJackson2JsonRedisSerializer
         * 后者会在json中加入@class属性，类的全路径包名，方便反序列化
         * Jackson2Jsonr如果存放了list，则在反序列化的时候，如果没有指定TypeReference
         * 会报错java.util.LinkedHashMap cannot be cast to
         */
        RedisSerializer genericJackson2JsonRedisSerializer =
                new GenericJackson2JsonRedisSerializer();
        RedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //定义RedisTemplate，并设置链接工程
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        //key的序列化采用StringRedisSerializer
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);

        //value的序列化采用GenericJackson2JsonRedisSerializer
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);

        //设置连接工程
        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate;
    }

    @Bean
    @ConditionalOnMissingBean({StringRedisTemplate.class})
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        //定义redisTemplage并设置链接工程
        StringRedisTemplate redisTemplate = new StringRedisTemplate(redisConnectionFactory);
        RedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setDefaultSerializer(stringRedisSerializer);
        redisTemplate.setEnableTransactionSupport(false);
        return redisTemplate;
    }
    @Bean
    public CacheManager initRedisCacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheManager.RedisCacheManagerBuilder builder =
                RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory);
        return builder.build();
    }

    @Bean
    RedisRepository redisRepository(RedisTemplate<Object, Object> redisTemplate){
        return new RedisRepository(redisTemplate);
    }

    @Bean(name = "redisRateLimitImpl")
    RedisRateLimitImpl redisRateLimit(RedisRateLimitProperties redisRateLimitProperties,
                                      StringRedisTemplate stringRedisTemplate)
    {
        return new RedisRateLimitImpl(redisRateLimitProperties, stringRedisTemplate);
    }
}
